#pragma once

#include <string>
#include <strings.h>
#include <functional>

/*网络必要的头文件*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*日志头文件*/
#include "logMessage.hpp"

#include <unistd.h>
#include <sys/wait.h>
#include "Protocol.hpp"

namespace server
{
    using namespace std;
    using namespace protocol;
    typedef function<bool(const Request &, Response &)> func_t;

    enum
    {
        SCOKET_ERROR = 1,
        BIND_ERROR,
        LISTEN_ERROR,
        START_ERROR,
        FATAL_ERROR,
        DIV_ZERO,
        MOD_ZERO,
        OPER_ERROR
    };

    /*1:获取请求
     *2:反序列化请求
     *3:处理业务,得到响应
     *4:序列化响应
     *5:发送*/
    void serviceTask(int sock, func_t func)
    {
        while (true)
        {
            /*1.获取请求*/
            string rqsStr;
            if (!getRequest(sock, rqsStr))
                return;
            cout << "get request success: " << rqsStr << endl;
            if (!delHeaders(rqsStr))
                return;
            cout << "delete headers success: " << rqsStr << endl;

            /*2.反序列化请求*/
            Request rqs;
            if (!rqs.deserialize(rqsStr))
                return;
            cout << "Request left: " << rqs._left << " right: " << rqs._right << " oper: " << rqs._oper << endl;

            /*3.业务处理*/
            Response rps;
            if (!func(rqs, rps))
                return;
            cout << "Response exitCode: " << rps._exitCode << " result: " << rps._result << endl;

            /*4.响应结果序列化*/
            string rpsStr;
            if (!rps.serialize(rpsStr))
                return;
            cout << "get responseStr: " << rpsStr << endl;
            
            /*5.发送响应结果*/
            string send_string = addHeaders(rpsStr);
            send(sock, send_string.c_str(), send_string.size(), 0);
            cout << "send success Str: " << rpsStr << endl;
        }
    }

    static const int gBacklog = 5;
    class tcpServer
    {
    public:
        tcpServer(const uint16_t &port)
            : _socketFd(-1), _port(port)
        {
            /*以字节流的方式打开网络文件，即TCP协议*/
            _socketFd = socket(AF_INET, SOCK_STREAM, 0);
            if (_socketFd == -1)
            {
                logMessage(FATAL, "socket failed");
                exit(SCOKET_ERROR);
            }
            logMessage(NORMAL, "socket success,socketFd[%d]", _socketFd);

            struct sockaddr_in server = getSockaddr_in();

            /*绑定套接字*/
            int n = bind(_socketFd, (struct sockaddr *)&server, sizeof(server));
            if (n == -1)
            {
                logMessage(FATAL, ":bind failed");
                exit(BIND_ERROR);
            }
            logMessage(NORMAL, "bind success,return value of bind[%d]", n);

            /*开始监听*/
            n = listen(_socketFd, gBacklog);
            if (n == -1)
            {
                logMessage(FATAL, "listen failed");
                exit(LISTEN_ERROR);
            }
            logMessage(NORMAL, "listen success,return value of listen[%d]", n);
        }

        void start(func_t func)
        {
            while (true)
            {
                struct sockaddr_in client = getSockaddr_in();
                socklen_t len = sizeof(client);
                int sock = accept(_socketFd, (struct sockaddr *)&client, &len);
                if (sock == -1)
                { /*如果accept失败，说明当前连接失败，不会影响其他连接*/
                    logMessage(ERROR, "accept failed,next...");
                    continue;
                }
                logMessage(NORMAL, "accept success,get a new sock[%d]", sock);

                processVersion(sock, func); /*多进程版本*/
            }
        }

    private:
        void processVersion(int sock, func_t func)
        {
            int id = fork();
            if (id == 0)
            {
                close(_socketFd);
                if (fork() > 0)
                    exit(0);
                serviceTask(sock, func);
                close(sock);
                exit(0);
            }
            pid_t ret = waitpid(id, nullptr, 0);
            if (ret > 0)
                logMessage(NORMAL, "wait child process success,child pid[%d]", ret);
        }

    private:
        /*服务端只关心端口号*/
        int _socketFd;
        uint16_t _port;

        /*将用于网络通信的结构体的设置封装成模块
         *由于编译器优化实际上只发生一次拷贝构造*/
        struct sockaddr_in getSockaddr_in()
        {
            struct sockaddr_in server;
            bzero((void *)&server, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(_port);
            server.sin_addr.s_addr = INADDR_ANY;
            return server;
        }
    };
} /*namespace server ends here*/